const express = require("express");
const http = require("http");
const socketIo = require("socket.io");
const mongoose = require("mongoose");
const amqp = require("amqplib/callback_api");
const Message = require("./models/message");
const User = require("./models/User");
const bcrypt = require("bcryptjs");
const jwt = require("jsonwebtoken");
const { body, validationResult } = require("express-validator");

const app = express();
const server = http.createServer(app);
const io = socketIo(server);

const activeUsers = {};

// 连接到 MongoDB
mongoose.connect("mongodb://localhost/chat", {
  useNewUrlParser: true,
  useUnifiedTopology: true,
});

// 中间件
app.use(express.json());
app.use(express.static("public"));

// RabbitMQ 连接和通道设置
let channel;
amqp.connect("amqp://localhost", (error0, connection) => {
  if (error0) {
    throw error0;
  }
  connection.createChannel((error1, ch) => {
    if (error1) {
      throw error1;
    }
    channel = ch;
    channel.assertQueue("chat_messages", { durable: true });
  });
});

// 注册路由
app.post(
  "/register",
  [
    body("username").isLength({ min: 3 }),
    body("password").isLength({ min: 5 }),
  ],
  async (req, res) => {
    const errors = validationResult(req);
    if (!errors.isEmpty()) {
      return res.status(400).json({ errors: errors.array() });
    }

    const { username, password } = req.body;
    const hashedPassword = await bcrypt.hash(password, 10);

    try {
      const newUser = new User({ username, password: hashedPassword });
      await newUser.save();
      res.status(201).json({ message: "User registered successfully!" });
    } catch (err) {
      res.status(500).json({ error: "User registration failed." });
    }
  }
);

// 登录路由
app.post("/login", async (req, res) => {
  const { username, password } = req.body;
  const user = await User.findOne({ username });

  if (!user || !(await bcrypt.compare(password, user.password))) {
    return res.status(401).json({ error: "Invalid username or password" });
  }

  const token = jwt.sign(
    { id: user._id, username: user.username },
    "your_jwt_secret",
    { expiresIn: "1h" }
  );
  res.json({ token });
});

// 获取聊天历史
app.get("/messages", async (req, res) => {
  const messages = await Message.find().sort({ createdAt: 1 });
  res.json(messages);
});

// 清空聊天记录的 API 端点
app.delete("/messages", async (req, res) => {
  try {
    await Message.deleteMany({});
    io.emit("clear messages"); // 向所有客户端广播清空消息的事件
    res.status(200).send("Chat history cleared");
  } catch (error) {
    res.status(500).send("Error clearing chat history");
  }
});

  // 认证中间件
const authenticateJWT = (req, res, next) => {
    const token = req.headers['authorization'] && req.headers['authorization'].split(' ')[1];
    if (token) {
        jwt.verify(token, 'your_jwt_secret', (err, user) => {
            if (err) {
                if (err.name === 'TokenExpiredError') {
                    // 如果 token 过期，返回 401 状态码和相应的信息
                    return res.status(401).json({ error: 'TokenExpired', message: 'Your session has expired. Please log in again.' });
                }
                return res.sendStatus(403);
            }
            req.user = user;
            next();
        });
    } else {
        res.sendStatus(401);
    }
};

// 添加好友的 API 端点
app.post("/add-friend", authenticateJWT, async (req, res) => {
    const { friendUsername } = req.body;
    const currentUser = await User.findById(req.user.id); // 获取当前用户的信息
  
    // 检查要添加的好友是否存在
    const friendUser = await User.findOne({ username: friendUsername });
    if (!friendUser) {
      return res.status(404).json({ error: "Friend not found." });
    }
  
    // 检查是否已经是好友
    if (currentUser.friends.includes(friendUser._id)) {
      return res.status(400).json({ error: "You are already friends." });
    }
  
    try {
      // 将好友添加到当前用户的好友列表中
      currentUser.friends.push(friendUser._id);
      await currentUser.save();
  
      // 将当前用户添加到好友的好友列表中（双向添加）
      friendUser.friends.push(currentUser._id);
      await friendUser.save();
  
      res.status(200).json({ message: "Friend added successfully." });
    } catch (error) {
      console.error(error);
      res.status(500).json({ error: "Failed to add friend." });
    }
  });

  // 获取好友的 API 端点
app.get("/get-friends", authenticateJWT, async (req, res) => {
    try {
      const currentUser = await User.findById(req.user.id).populate("friends", "username"); // 获取当前用户的好友，填充好友的用户名
  
      if (!currentUser) {
        return res.status(404).json({ error: "User not found." });
      }
  
      res.status(200).json(currentUser.friends); // 返回好友列表
    } catch (error) {
      console.error(error);
      res.status(500).json({ error: "Failed to retrieve friends." });
    }
  });
  

// 处理连接
io.use((socket, next) => {
  const token = socket.handshake.query.token; // 从查询参数中获取 token
  if (token) {
    jwt.verify(token, "your_jwt_secret", (err, user) => {
      if (err) {
        console.log(err);
        return next(new Error("Authentication error"));
      }
      socket.user = user; // 将用户信息存储在 socket 中
      next();
    });
  } else {
    next(new Error("Authentication error"));
  }
}).on("connection", (socket) => {
  console.log("a user connected", socket.user.username); // 打印用户名

  // 检查当前用户是否已经在线
  if (activeUsers[socket.user.username]) {
    // 如果在线，断开之前的连接
    activeUsers[socket.user.username].disconnect();
    console.log(`${socket.user.username} was disconnected due to a new login.`);
  }

  // 将当前用户的 Socket 连接存储在 activeUsers 对象中
  activeUsers[socket.user.username] = socket;
  console.log(activeUsers);

  // 广播更新后的在线用户列表
  io.emit("update user list", Object.keys(activeUsers));

  // 监听私聊消息
  socket.on("private message", ({ recipient, message }) => {
    const recipientSocketId = activeUsers[recipient].id;
    if (recipientSocketId) {
      io.to(recipientSocketId).emit("private message", {
        sender: socket.user.username,
        message,
      });
    }
  });

  // 接收消息并发布到 RabbitMQ 队列
  socket.on("chat message", (msg) => {
    const messageContent = `${socket.user.username}: ${msg}`; // 在消息前添加用户名
    const message = new Message({
      content: messageContent,
      sender: socket.user.username,
    });
    message.save().then((savedMessage) => {
      channel.sendToQueue(
        "chat_messages",
        Buffer.from(JSON.stringify(savedMessage))
      );
    });
  });

  // 撤回消息
  socket.on("revoke message", (messageId) => {
    Message.findById(messageId).then((message) => {
      if (message && message.sender === socket.user.username) {
        Message.findByIdAndDelete(messageId).then(() => {
          io.emit("revoke message", messageId);
        });
      } else {
        socket.emit("error", "You can only revoke your own messages.");
      }
    });
  });

  // 消费来自 RabbitMQ 队列的消息，并广播给所有客户端
  channel.consume("chat_messages", (msg) => {
    if (msg !== null) {
      const message = JSON.parse(msg.content.toString());
      io.emit("chat message", message);
      channel.ack(msg);
    }
  });

  // 处理断开连接
  socket.on("disconnect", () => {
    delete activeUsers[socket.user.username];
    console.log("user disconnected");

    // 广播更新后的在线用户列表
    io.emit("update user list", Object.keys(activeUsers));
  });
});

// 监听端口
const PORT = 3000;
server.listen(PORT, () => {
  console.log(`Server is running on http://localhost:${PORT}`);
});
